package com.oracle2mysql.migration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 * MyBatis XML解析器，负责解析和转换MyBatis映射文件
 */
public class MyBatisXmlParser {
    
    private static final Logger logger = LoggerFactory.getLogger(MyBatisXmlParser.class);
    private SqlConverter sqlConverter;
    private Properties config;
    private boolean overwrite;
    
    public MyBatisXmlParser(SqlConverter sqlConverter, Properties config) {
        this.sqlConverter = sqlConverter;
        this.config = config;
        // 从配置中获取是否覆盖已有文件的设置
        this.overwrite = Boolean.parseBoolean(config.getProperty("overwrite", "true"));
    }
    
    /**
     * 处理指定目录下的所有MyBatis XML文件
     */
    public void processDirectory(String inputDir, String outputDir) throws Exception {
        File inputFolder = new File(inputDir);
        File outputFolder = new File(outputDir);
        
        // 检查输入目录是否存在
        if (!inputFolder.exists()) {
            logger.error("输入目录不存在: {}", inputFolder.getAbsolutePath());
            throw new IllegalArgumentException("输入目录不存在: " + inputFolder.getAbsolutePath());
        }
        
        // 检查输入是否为目录
        if (!inputFolder.isDirectory()) {
            logger.error("输入路径不是一个目录: {}", inputFolder.getAbsolutePath());
            throw new IllegalArgumentException("输入路径不是一个目录: " + inputFolder.getAbsolutePath());
        }
        
        // 创建输出目录
        if (!outputFolder.exists()) {
            outputFolder.mkdirs();
        }
        
        // 处理目录下的所有文件
        File[] files = inputFolder.listFiles();
        if (files == null) {
            logger.warn("无法访问输入目录或目录为空: {}", inputFolder.getAbsolutePath());
            return;
        }
        
        boolean hasProcessedFiles = false;
        for (File file : files) {
            if (file.isDirectory()) {
                // 递归处理子目录
                String subInputDir = inputDir + File.separator + file.getName();
                String subOutputDir = outputDir + File.separator + file.getName();
                processDirectory(subInputDir, subOutputDir);
            } else if (file.getName().endsWith(".xml")) {
                // 处理XML文件
                processFile(file, new File(outputDir + File.separator + file.getName()));
                hasProcessedFiles = true;
            }
        }
        
        if (!hasProcessedFiles) {
            logger.info("在输入目录中未找到需要处理的XML文件: {}", inputFolder.getAbsolutePath());
        }
    }
    
    /**
     * 处理单个MyBatis XML文件
     */
    public void processFile(File inputFile, File outputFile) throws Exception {
        logger.info("处理文件: {}", inputFile.getPath());
        
        // 检查是否应该覆盖已存在的文件
        if (outputFile.exists() && !overwrite) {
            logger.info("文件已存在且overwrite=false，跳过: {}", outputFile.getPath());
            return;
        }
        
        // 解析XML文档
        Document document = parseXmlFile(inputFile);
        
        // 转换SQL语句
        transformSqlStatements(document);
        
        // 保存转换后的XML文件
        saveXmlFile(document, outputFile);
        
        logger.info("已保存转换后的文件: {}", outputFile.getPath());
    }
    
    /**
     * 解析XML文件
     */
    private Document parseXmlFile(File file) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        
        // 禁用外部DTD解析，避免连接超时
        factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        factory.setXIncludeAware(false);
        factory.setValidating(false);
        
        DocumentBuilder builder = factory.newDocumentBuilder();
        
        try (FileInputStream fis = new FileInputStream(file)) {
            return builder.parse(new InputSource(fis));
        }
    }
    
    /**
     * 转换XML中的SQL语句
     */
    private void transformSqlStatements(Document document) {
        // 获取所有SQL相关的元素
        NodeList selectNodes = document.getElementsByTagName("select");
        NodeList insertNodes = document.getElementsByTagName("insert");
        NodeList updateNodes = document.getElementsByTagName("update");
        NodeList deleteNodes = document.getElementsByTagName("delete");
        NodeList sqlNodes = document.getElementsByTagName("sql");
        
        // 处理各种SQL元素
        processSqlElements(selectNodes);
        processSqlElements(insertNodes);
        processSqlElements(updateNodes);
        processSqlElements(deleteNodes);
        processSqlElements(sqlNodes);
    }
    
    /**
     * 处理SQL元素节点
     */
    private void processSqlElements(NodeList nodeList) {
        int convertedCount = 0;
        
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) node;
                String sqlText = element.getTextContent();
                
                if (sqlText != null && !sqlText.trim().isEmpty()) {
                    // 转换SQL
                    String convertedSql = sqlConverter.convert(sqlText);
                    
                    // 更新元素内容
                    element.setTextContent(convertedSql);
                    convertedCount++;
                }
            }
        }
        
        if (convertedCount > 0) {
            logger.debug("已转换 {} 个SQL语句", convertedCount);
        }
    }
    
    /**
     * 保存XML文件
     */
    private void saveXmlFile(Document document, File outputFile) throws Exception {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        
        // 设置输出属性
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        
        DOMSource source = new DOMSource(document);
        
        // 确保父目录存在
        File parentDir = outputFile.getParentFile();
        if (!parentDir.exists()) {
            parentDir.mkdirs();
        }
        
        try (FileOutputStream fos = new FileOutputStream(outputFile)) {
            StreamResult result = new StreamResult(fos);
            transformer.transform(source, result);
        }
    }
}